package com.yiren.dbaa.module.practice_set.basestation.presenter;

import android.app.Activity;
import android.os.Handler;

import com.yiren.backstage.communication.api.impl.BluetoothCommunicationApiImpl;
import com.yiren.backstage.currency.bean.GpsInfoBean;
import com.yiren.backstage.currency.constant.Messages4G;
import com.yiren.backstage.currency.constant.SignalGConstant;
import com.yiren.backstage.currency.utils.StringUtil;
import com.yiren.dbaa.currency.api.CommonCallBack;
import com.yiren.dbaa.module.practice_set.basestation.bean.BaseStationBean;
import com.yiren.dbaa.module.practice_set.basestation.contract.CalibrationContract;
import com.yiren.dbaa.module.practice_set.basestation.model.CalibrationModel;
import com.yiren.dbaa.util.DecimalTransferUtil;
import com.yiren.dbaa.util.DistanceUtil;
import com.yiren.dbaa.view.dialog.LoadDialog;
import com.yiren.dbaa.view.toast.MessageBox;

import org.apache.commons.lang.StringUtils;

import java.util.regex.Pattern;

/**
 * @author lwb
 * @date : 2022/12/14 11:07
 * @description: 基站标定
 */
public class CalibrationPresenter implements CalibrationContract.Presenter {

    private Activity activity;
    private Handler handler;
    private CalibrationContract.Model calibrationModel;
    private CalibrationContract.CalibrationView calibrationView;
    private CalibrationContract.BaseManageView manageView;

    private String command = "mode base time 60 1.5 2.5"; //接收机自主定位 60 秒；或者水平定位标准差<=1.5m，且高程定位标准差<=2.5m 时，把水平定位的平均值和高程定位的平均值作为基准站坐标值断电重启后，将重复计算并生成新基准点坐标
    private String atCfgEnd = "AT+CFG_END\r\n";
    /*** 标定基站的指令 */
    private String baseCalibration = "";
    /*** 匹配所有数字和带小数点的数字 */
    private String regex = "([1-9]\\d*\\.?\\d*)|(0\\.\\d*[1-9])";

    /*** 固定基站id */
    private BaseStationBean baseStationBean;
    /*** 是否上传固定基站位置 */
    private boolean isUpload;
    /*** 标定后基站的经度 */
    private String longitude;
    /*** 标定后基站的纬度 */
    private String latitude;
    /*** 标定后基站的高度 */
    private String altitude;

    /*** 取经纬度第几帧的数据 */
    private int value = 0;
    /***经纬度差值小于规定值的次数 */
    private int trueValue = 0;
    /***固定基站标定成功的步骤 1、先返回saveconfig,response: OK标识 2、接着出现$GPGGA数据 */
    private int step = 0;

    private CMDThread cmdThread;
    private Runnable stateInfoRunnable;

    public CalibrationPresenter(Activity activity) {
        this.activity = activity;
        calibrationModel = new CalibrationModel(activity);
        handler = new Handler();
    }

    @Override
    public void calibrationBaseStation(BaseStationBean baseStationBean, CalibrationContract.CalibrationView view) {
        this.baseStationBean = baseStationBean;
        this.calibrationView = view;
        value = 0;
        trueValue = 0;
        isUpload = false;
        if (SignalGConstant.isOpen) {
            if (null == baseStationBean) {  //新建基站
                LoadDialog.show(activity, "正在获取基站信息，请稍后...", false);
                startCMD(0);
            } else {
                LoadDialog.show(activity, "移动站配置中，请稍后...", false);
                startCMD(1);
            }
        } else {
            MessageBox.show(activity, "请先去蓝牙工具里面连接移动基站蓝牙");
        }
    }

    @Override
    public void removeThread() {
        if (cmdThread != null) cmdThread.cancel();
        handler.removeCallbacks(stateInfoRunnable);
    }

    @Override
    public void getNewBaseBoxId(CalibrationContract.BaseManageView view) {
        this.manageView = view;
        if (SignalGConstant.isOpen) {
            LoadDialog.show(activity, "正在获取基站信息，请稍后...", false);
            startCMD(0);
        } else {
            MessageBox.show(activity, "请先去蓝牙工具里面连接移动基站蓝牙");
        }
    }

    @Override
    public void replaceBaseBoxId(String oldBaseId, String newBaseId, CalibrationContract.BaseManageView view) {
        calibrationModel.updateBaseBoxId(oldBaseId, newBaseId, new CommonCallBack() {
            @Override
            public void success(Object result) {
                view.updateBaseIdSuccess(newBaseId);
            }

            @Override
            public void fail(String error) {
                MessageBox.show(activity, error);
            }
        });
    }

    @Override
    public void replaceBaseBoxName(String baseId, String baseName, CalibrationContract.BaseManageView view) {
        calibrationModel.updateBaseBoxName(baseId, baseName, new CommonCallBack() {
            @Override
            public void success(Object result) {
                view.updateBaseNameSuccess(baseName);
            }

            @Override
            public void fail(String error) {
                MessageBox.show(activity, error);
            }
        });
    }

    /**
     * 启动CMD线程
     *
     * @param index
     */
    private void startCMD(int index) {
        if (cmdThread != null) cmdThread.cancel();
        if (index == 2) step = 0;
        cmdThread = new CMDThread();
        cmdThread.index = index;
        cmdThread.start();
        refresh();
    }

    private void refresh() {
        stateInfoRunnable = new Runnable() {
            @Override
            public void run() {
                if (cmdThread.index == 0) {
                    if (SignalGConstant.allData.contains("REGDT") && !SignalGConstant.allData.contains("$")) {
                        String baseId = SignalGConstant.allData.split(":")[1];
                        cmdThread.index = -1;
                        try {
                            Thread.sleep(1500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        if (null != manageView) {  //这里是更换基站盒获取到了基站id
                            manageView.setBaseId(baseId);
                            LoadDialog.dismiss(activity);
                        }
                        if (null != calibrationView) {
                            //这里是基站标定，获取到了基站id，接下来开始标定流程
                            baseStationBean.setId(baseId);
                            calibrationView.setBaseId(baseId);
                            startCMD(1);
                        }
                    }
                } else if (cmdThread.index == 1) {
                    if (SignalGConstant.allData.contains("gpgga 1,response: OK") || SignalGConstant.allData.contains("saveconfig,response: OK")) {
                        cmdThread.index = -1;
                        LoadDialog.dismiss(activity);
                        activity.runOnUiThread(() -> LoadDialog.show(activity, "开始获取基站位置，请稍后..."));
                    }
                } else if (cmdThread.index == 2) {
//                        getStationStatus();
//                        if (SignalG.allData.contains("gpgga 1,response: OK") || SignalG.allData.contains("saveconfig,response: OK")) {
                    if (SignalGConstant.allData.contains("saveconfig,response: OK")) {
                        //有时候会卡在这个保存配置的指令上麦，没有$GPGGA数据发过来
                        step = 1;
                    }
                    //这里等到保存配置成功之后看是否有$GPGGA数据返回，如果有，则成功切换成固定站
                    if (step == 1 && SignalGConstant.allData.startsWith("$GPGGA")) {
                        LoadDialog.dismiss(activity);
                    }
                }
                if (SignalGConstant.allData.contains("$KSXT")) {
                    String[] arrayOfString = SignalGConstant.allData.split(",");
                    if (arrayOfString.length > 10 && Pattern.matches(regex, arrayOfString[10])) {
                        float satelliteNum = Float.parseFloat(arrayOfString[10]);
                        activity.runOnUiThread(() -> calibrationView.setPositionStatus(satelliteNum));
                        if (satelliteNum == 3) {
                            value++;
                            if (value % 100 == 1 || value % 100 == 2) {
                                longitude = arrayOfString[2];
                                latitude = arrayOfString[3];
                                altitude = arrayOfString[4];
                            }
                            activity.runOnUiThread(() -> calibrationView.setBaseLocation(longitude, latitude, altitude));
                            double deltLongitude = Math.abs(Double.parseDouble(arrayOfString[2]) - Double.parseDouble(longitude));
                            double deltLatitude = Math.abs(Double.parseDouble(arrayOfString[3]) - Double.parseDouble(latitude));
                            if (deltLongitude < 0.0000003 && deltLatitude < 0.0000003) {
                                trueValue++;
                            } else {
                                value = 0;
                                trueValue = 0;
                            }
                            if (trueValue > 100) {
                                //记录100次相对值小于3公分的经纬度，作为上传基站的经纬度
                                GpsInfoBean gps = GpsInfoBean.getInstance();
                                String address = gps.getCity() + gps.getArea() + gps.getStreet();
                                String distance = DecimalTransferUtil.readableMeter(DistanceUtil.getBaseDistance(gps));
                                baseStationBean.setLocationInfo(Double.parseDouble(longitude), Double.parseDouble(latitude), Double.parseDouble(altitude), address, Float.parseFloat(distance));
                                activity.runOnUiThread(() -> calibrationView.setBaseLocation(longitude, latitude, altitude, address, distance));
                                baseCalibration = "mode base " + latitude + " " + longitude + " " + altitude;
                                if (cmdThread.index != 2) {
                                    LoadDialog.dismiss(activity);
                                    activity.runOnUiThread(() -> LoadDialog.show(activity, "开始标定基站位置，请稍后..."));
                                    startCMD(2); //TODO TAG1
                                }
                            }
                        }
                    }
                    if (cmdThread.index == 2 && trueValue % 150 == 0) {
                        //有时候TAG1处切换固定站模式没有生效，这里每隔150个值重新发送一次指令
                        startCMD(2);
                    }
                }
                getStationStatus();
                activity.runOnUiThread(() -> calibrationView.setCalibrationEdit());
                handler.postDelayed(this, 50);
            }
        };
        stateInfoRunnable.run();
    }

    /**
     * 获取基站标定状态并上传基站位置信息
     */
    private void getStationStatus() {
        if (SignalGConstant.allData.contains("mode base")) {
            if (SignalGConstant.allData.contains("mode base time")) {
            } else if (StringUtil.contains("mode base .*,response: OK", SignalGConstant.allData)) {
                //mode base 28.179581957994134 112.92939319095109 75.3553,response: OK*61
                if (!isUpload && null != baseStationBean) {
                    isUpload = true;
                    calibrationModel.uploadBaseStation(baseStationBean, new CommonCallBack() {
                        @Override
                        public void success(Object result) {
                            MessageBox.MessageAndVoiceModel(activity, "固定基站标定成功！");
                            activity.runOnUiThread(() -> calibrationView.setCalibrationSuccess());
                        }

                        @Override
                        public void fail(String error) {
                            MessageBox.show(activity, error);
                        }
                    });
                }
            }
        }
    }

    private class CMDThread extends Thread {
        String[][] cmds = new String[][]{{
//                "AT+MODE=CFG_RTK\r\n",  //配置RTK模块
//                "unlogall",             //停止输出所有log
//                "CONFIG INS DISABLE",   //关闭惯导
//                command,                //接收机自主定位 60 秒；或者水平定位标准差<=1.5m，且高程定位标准差<=2.5m 时，把水平定位的平均值和高程定位的平均值作为基准站坐标值断电重启后，将重复计算并生成新基准点坐标
//                "rtcm1006 com2 10",     //RTK 基准站天线参考点坐标（含天线高）
//                "rtcm1033 com2 10",     //接收机和天线说明
//                "rtcm1074 com2 1",      //GPS 差分电文
//                "rtcm1124 com2 1",      //BDS 差分电文
//                "rtcm1084 com2 1",      //GLO 差分电文
//                "rtcm1094 com2 1",      //Galileo 差分电文
//                "gpgga 1",              //当前串口输出 1Hz 的 GPGGA 信息
//                "saveconfig",           //保存用户配置到非易失性存储器（NVM）中
//                "AT+CFG_END\r\n"        //配置结束
                Messages4G.FOURG3,
                Messages4G.FOURG13,
                Messages4G.FOURG4
        }, {
                "AT+MODE=CFG_RTK\r\n",  //配置RTK模块
                "unlogall",             //停止输出所有log
                "CONFIG INS DISABLE",   //关闭惯导
                "mode movingbase",      //设置为移动基准站
                "mode rover",           //缺省 Rover 模式（该指令可使接收机从基站模式转换到流动站模式）
                "ksxt 0.2",             //当前串口输出 5Hz 的 KSXT 信息
                "gpgga 1",              //当前串口输出 1Hz 的 GPGGA 信息
                "saveconfig",           //保存用户配置到非易失性存储器（NVM）中
                atCfgEnd                //配置结束
        }, {
                "AT+MODE=CFG_RTK\r\n",  //配置RTK模块
                "unlogall",             //停止输出所有log
                "CONFIG INS DISABLE",   //关闭惯导
//                command,                //接收机自主定位 60 秒；或者水平定位标准差<=1.5m，且高程定位标准差<=2.5m 时，把水平定位的平均值和高程定位的平均值作为基准站坐标值断电重启后，将重复计算并生成新基准点坐标
                baseCalibration,        //标定基站位置
                "rtcm1006 com2 10",     //RTK 基准站天线参考点坐标（含天线高）
                "rtcm1033 com2 10",     //接收机和天线说明
                "rtcm1074 com2 1",      //GPS 差分电文
                "rtcm1124 com2 1",      //BDS 差分电文
                "rtcm1084 com2 1",      //GLO 差分电文
                "rtcm1094 com2 1",      //Galileo 差分电文
                "gpgga 1",              //当前串口输出 1Hz 的 GPGGA 信息
                "saveconfig",           //保存用户配置到非易失性存储器（NVM）中
                "AT+CFG_END\r\n"        //配置结束
        }};

        private boolean isRunning;
        private int index = -1;

        @Override
        public void run() {
            isRunning = 0 <= index && index < cmds.length;
            if (isRunning) {
                String[] cmd = cmds[index];
                for (int i = 0; i < cmd.length && isRunning; i++) {
                    try {
                        //connectThread.writeLine(cmd[i]);
                        cmd[i] += "\r\n";
                        BluetoothCommunicationApiImpl.getInstance(activity).writeData(cmd[i].getBytes(), "", null);
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            isRunning = false;
        }

        void cancel() {
            isRunning = false;
        }
    }

}